﻿using System;
using System.ComponentModel;
using System.Globalization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WindowsPhoneEssentials.Settings;
using WindowsPhoneEssentials.Testing.Abstractions;

namespace WindowsPhoneEssentials.Tests.Settings
{
    [TestClass]
    public class SettingsProviderTests
    {
        private FakeIsolatedStorageSettings applicationSettingsStore;
        private SettingsProvider settingsRetreiver;
        private SettingsProvider settingsSaver;

        [TestInitialize]
        public void Setup()
        {
            applicationSettingsStore = new FakeIsolatedStorageSettings();
            settingsRetreiver = new SettingsProvider(applicationSettingsStore);
            settingsSaver = new SettingsProvider(applicationSettingsStore);
        }

        [TestMethod]
        public void settings_provider_can_persist_int()
        {
            // arrange
            var settings = new TestSettings { TestProp2 = 123 };
            var settingDescriptor = new SettingsProvider.SettingDescriptor(typeof(TestSettings).GetProperty("TestProp2"));
            var key = SettingsProvider.GetKey<TestSettings>(settingDescriptor);

            // act
            settingsSaver.SaveSettings(settings);

            // assert
            Assert.AreEqual(settings.TestProp2, Convert.ToInt32(applicationSettingsStore[key]));
        }

        [TestMethod]
        public void settings_provider_can_retreive_int()
        {
            // arrange
            settingsSaver.SaveSettings(new TestSettings { TestProp2 = 123 });

            // act
            var settings = settingsRetreiver.GetSettings<TestSettings>();

            // assert
            Assert.AreEqual(settings.TestProp2, 123);
        }

        [TestMethod]
        public void settings_provider_can_persist_string()
        {
            // arrange
            var settings = new TestSettings { TestProp1 = "foo" };
            var settingDescriptor = new SettingsProvider.SettingDescriptor(typeof(TestSettings).GetProperty("TestProp1"));
            var key = SettingsProvider.GetKey<TestSettings>(settingDescriptor);

            // act
            settingsSaver.SaveSettings(settings);

            // assert
            Assert.AreEqual(settings.TestProp1, applicationSettingsStore[key]);
        }

        [TestMethod]
        public void settings_provider_can_retreive_string()
        {
            // arrange
            settingsSaver.SaveSettings(new TestSettings { TestProp1 = "foo" });

            // act
            var settings = settingsRetreiver.GetSettings<TestSettings>();

            // assert
            Assert.AreEqual("foo", settings.TestProp1);
        }

        [TestMethod]
        public void settings_provider_can_persist_nullable_datetime()
        {
            // arrange
            var firstRun = DateTime.Now;
            var settings = new TestSettings { FirstRun = firstRun };
            var settingDescriptor = new SettingsProvider.SettingDescriptor(typeof(TestSettings).GetProperty("FirstRun"));
            var key = SettingsProvider.GetKey<TestSettings>(settingDescriptor);

            // act
            settingsSaver.SaveSettings(settings);

            // assert
            Assert.AreEqual(firstRun.ToString(CultureInfo.InvariantCulture), applicationSettingsStore[key]);
        }

        [TestMethod]
        public void settings_provider_can_retreive_nullable_datetime()
        {
            // arrange
            var firstRun = DateTime.Now;
            settingsSaver.SaveSettings(new TestSettings { FirstRun = firstRun });

            // act
            var settings = settingsRetreiver.GetSettings<TestSettings>();

            // assert
            Assert.AreEqual(firstRun.ToString(), settings.FirstRun.ToString());
        }

        [TestMethod]
        public void settings_provider_can_retreive_null_nullable_datetime()
        {
            // arrange
            settingsSaver.SaveSettings(new TestSettings { FirstRun = null });

            // act
            var settings = settingsRetreiver.GetSettings<TestSettings>();

            // assert
            Assert.IsNull(settings.FirstRun);
        }

        [TestMethod]
        public void settings_provider_loads_default_values()
        {
            // arrange

            // act
            var settings = settingsRetreiver.GetSettings<TestSettings>();

            // assert
            Assert.AreEqual("foo", settings.TestProp1);
        }

        [TestMethod]
        public void settings_provider_ignores_properties_with_no_setters()
        {
            // arrange

            // act
            var settings = settingsRetreiver.GetSettings<TestSettings>();

            // assert
            Assert.IsNotNull(settings.Complex);
        }

        [TestMethod]
        public void settings_provider_can_persist_enum()
        {
            // arrange
            var settings = new TestSettings { SomeEnum = MyEnum.Value1 };
            var settingDescriptor = new SettingsProvider.SettingDescriptor(typeof(TestSettings).GetProperty("SomeEnum"));
            var key = SettingsProvider.GetKey<TestSettings>(settingDescriptor);

            // act
            settingsSaver.SaveSettings(settings);

            // assert
            Assert.AreEqual(settings.SomeEnum.ToString(), applicationSettingsStore[key]);
        }

        [TestMethod]
        public void settings_provider_can_retreive_enum()
        {
            // arrange
            settingsSaver.SaveSettings(new TestSettings { SomeEnum = MyEnum.Value2 });

            // act
            var settings = settingsRetreiver.GetSettings<TestSettings>();

            // assert
            Assert.AreEqual(MyEnum.Value2, settings.SomeEnum);
        }

        public class TestSettings : ISettings
        {
            [DefaultValue("foo")]
            public string TestProp1 { get; set; }

            public MyEnum SomeEnum { get; set; }

            public int TestProp2 { get; set; }

            public DateTime? FirstRun { get; set; }

            public ComplexType Complex { get{ return new ComplexType();}}

            public class ComplexType
            {
            }
        }
    }

    public enum MyEnum
    {
        Value1,
        Value2
    }
}
